#ifndef _MAPPING_VIEW
#define _MAPPING_VIEW

namespace math { namespace ui {

class MappingView  : public GLView 
{
public:
	typedef float value_type ;
	typedef math::vector<value_type, 2> vector2 ;
	typedef math::vector<value_type, 3> vector3 ;
	typedef math::vector<value_type, 2> point2 ;
	typedef math::vector<value_type, 3> point3 ;

	typedef math::HierarchyMesh<math::hierarchy_mesh_traits<value_type, 3> >  mesh_type ;
	typedef math::PseudoMesh<value_type , 3> pseudomesh_type ;
	typedef math::hierarchy_mesh_traits <value_type, 3>::FaceType face_type ;

	MappingView (Model * model, unsigned ID) : GLView(model, ID) , mp_brush(NULL)
	{ this->mp_model = model ;
		this->mp_brush = mp_model->get_brush() ;}
	~ MappingView () {}
	virtual void set_shader (Shader * shader) {this->mp_shader = shader ;}
	virtual void set_viewmode (DISPLAY_MODE vm = FILL_MODE)
	{
		mainView.display_mode = vm ;
	}

	virtual void setMousePos (int _x, int _y)
	{
		mainView.mouse_winpos = _x, _y; 
		this->mp_brush->set_win_pos (vector2 (_x, _y)); 
	}

	virtual void setLButtonDown (bool flag = true)
	{
		this->mainView.mouseLeftDown = flag;
	}
	virtual void setRButtonDown (bool flag = true)
	{
		this->mainView.mouseRightDown = flag;
	}

	virtual void setMButtonDown (bool flag = true)
	{
		this->mainView.mouseMiddleDown = flag;
	}
	virtual void rotateCamera (int x, int y)
	{

		mainView.cameraAglY += (x - mainView.mouse_winpos.x);
		mainView.cameraAglX += (y - mainView.mouse_winpos.y);

		mainView.mouse_winpos = x, y; 
	}
	virtual void translateCamera (int x, int y)
	{
		mainView.focus.x += 0.005 * (x - mainView.mouse_winpos.x);
		mainView.focus.y -= 0.005 * (y - mainView.mouse_winpos.y);

		mainView.mouse_winpos = x, y;
	}
	virtual void zoomCamera(int x, int y)
	{
		mainView.focus.z -= (y - mainView.mouse_winpos.y) * 0.01f;
		mainView.mouse_winpos.y = y;

	}

	virtual void resize (int w, int h)
	{
		this->mp_brush->set_winsize (this->m_width, this->m_height) ;
	}



	inline void enable_shader () const {mp_shader->set_uniform("draw_face", 1); }
	inline void disable_shader () const {mp_shader->set_uniform("draw_face", 0); }

	virtual void paint () 
	{

		// scissor the region
		set_scissor(); 
		// Set the left view
		setViewport(this->m_xpos, this->m_ypos, this->m_width, this->m_height, mainView.projectionNear, mainView.projectionFar);
		setViewMode(mainView.display_mode);

		glPushMatrix();
		glTranslatef(mainView.focus.x, mainView.focus.y, mainView.focus.z);
//		glRotatef(mainView.cameraAglX, 1, 0, 0); // pitch
//		glRotatef(mainView.cameraAglY, 0, 1, 0); // heading

		//glClearColor(0.0f, 0.0f, 0.0f, 1);
		color_type & c = this->mainView.backgroundColor  ;
		glClearColor(c[0], c[1], c[2], c[3]);

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
		draw_grid(10, 1);
		//	glColor3f(1.0, 1.0, 1.0);
//		mp_brush->getObjCoordEnv(); 
		mp_brush->texVM.getCoordEnv(); 
		sence();
		glPopMatrix(); 

		glPushMatrix();
		glLoadIdentity();
		glTranslatef(0, 0, -0.01);
//		glRotatef(0.707, 1, 0, 0);
		mp_brush->getBrushCoordEnv(); 

		mp_brush->draw(); 

		glPopMatrix(); 

		
	}

	typedef Segment<value_type, 3> segment_type ;
	void pick_face ()
	{
		point3 p1, p2;
		mp_brush->pick_ray(p1, p2);

		std::vector <unsigned > v_face_id ;
		mp_model->get_mesh()->pick(segment_type (p1, p2), v_face_id) ;
		if (v_face_id.size() > 0) 
		{
			face_type * face = mp_model->get_mesh()->faces[v_face_id[0]] ;
			face->set_selected(! face->is_selected());
		}

	}

	void draw_mesh_facet (mesh_type * mesh)
	{
		enable_shader (); 
		for (unsigned i = 0; i < mesh->faces.size(); ++i)
		{
			if (mesh->faces[i]->get_tagged()) mesh->faces[i]->draw_flat(); 
		}
		disable_shader (); 
	}


	void draw_mesh_facet (pseudomesh_type * mesh)
	{
//		set_viewmode(FRAME_MODE);
//		std::cout<<"FACE SIZE "<<mesh->faces.size()<<std::endl;
		for (unsigned i = 0; i < mesh->faces.size(); ++i)
		{
			if (mesh->faces[i]->is_selected()) mesh->faces[i]->draw_tex_blend(); 
		}

		enable_shader (); 
		for (unsigned i = 0; i < mesh->faces.size(); ++i)
		{
			//if (mesh->faces[i]->get_tagged()) mesh->faces[i]->draw(); 
			//mesh->faces[i]->draw(); 
			mesh->faces[i]->draw_texcoord(); 
		}
		disable_shader (); 

	}


	void sence () 
	{	
		glEnable(GL_TEXTURE_2D);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
//		mesh_type * pmesh = mp_model->get_mesh (); 
		pseudomesh_type * pmesh = mp_model->get_pseudomesh(); 
		draw_mesh_facet(pmesh);
		glFlush();		
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);
	}

	void draw_grid(float size, float step)
	{
		// disable lighting
		glDisable(GL_LIGHTING);
		glBegin(GL_LINES);
		glColor3f(0.3f, 0.3f, 0.3f);
		float offset = 0.0f;
		for(float i=step; i <= size; i+= step)
		{
			glVertex3f(-size, offset,  i);   // lines parallel to X-axis
			glVertex3f( size, offset,  i);
			glVertex3f(-size, offset, -i);   // lines parallel to X-axis
			glVertex3f( size, offset, -i);

			glVertex3f( i, offset, -size);   // lines parallel to Z-axis
			glVertex3f( i, offset,  size);
			glVertex3f(-i, offset, -size);   // lines parallel to Z-axis
			glVertex3f(-i, offset,  size);
		}

		// x-axis
		glColor3f(0.5f, offset, 0);
		glVertex3f(-size, offset, 0);
		glVertex3f( size, offset, 0);

		// z-axis
		glColor3f(0,offset,0.5f);
		glVertex3f(0, offset, -size);
		glVertex3f(0, offset,  size);

		glEnd();
		glEnable(GL_LIGHTING);
		glFlush();
	}

protected :

private: 
	Shader * mp_shader ;
	Brush * mp_brush ;
};

	}}

#endif
